package com.github.llyb120.driver.qiuya;

import com.github.llyb120.driver.qiuya.request.ReqAggregate;
import com.github.llyb120.json.Arr;
import com.github.llyb120.json.Obj;
import org.bson.Document;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;

import static com.github.llyb120.driver.qiuya.request.ReqBase.COMMAND_AGGREGATE;
import static com.github.llyb120.json.Json.a;
import static com.github.llyb120.json.Json.o;

public class Query {
    private Collection collection;
    Arr built;
    Map $match;
    private Map $sort = null;
    private Integer $skip = null;
    private Integer $limit = null;


    public Query(Collection collection){
        this.collection = collection;
    }

    public Query sort(Document document){
        $sort = document;
        return this;
    }

    public Query skip(int n){
        $skip = n;
        return this;
    }

    public Query limit(int n){
        $limit = n;
        return this;
    }

    private void fix(){
        //因为GO的map不支持排序，所以需要处理一下
        for (Object o : built) {
            Map item = (Map) o;
            if(!item.containsKey("$sort")){
                continue;
            }
            Map val = (Map) item.get("$sort");
            //
            Arr newVal = a();
            for (Object o1 : val.entrySet()) {
                Map.Entry entry = (Map.Entry) o1;
                newVal.add(a(entry.getKey(), entry.getValue()));
            }
            item.put("$sort", newVal);
        }
    }

    //mongo
    public <T extends List> T into(T container){
        build();
        fix();
        try {
            Obj obj = this.collection.database.client.ws.send(COMMAND_AGGREGATE, new ReqAggregate(collection.database.name, collection.name, built)).get();
            if(!obj.ss("code").equals("0")){
                throw new RuntimeException();
            }
            List<Document> list = obj.aa("data").stream()
                    .map(e -> Document.parse(e.toString()))
                    .collect(Collectors.toList());
            container.addAll(list);
            return (T) list;
        } catch (InterruptedException | ExecutionException e) {
            throw new RuntimeException(e);
        }
    }

    public Document first(){
        $limit = 1;
        build();
        fix();
        List<Document> res = into(a());
        if (!res.isEmpty()) {
            return res.get(0);
        }
        return null;
    }

    Query build(){
        built = a();
        if ($match != null) {
            built.add(o("$match", $match));
        }
        if ($sort != null) {
            built.add(o("$sort", $sort));
        }
        if ($skip != null) {
            built.add(o("$skip", $skip));
        }
        if ($limit != null) {
            built.add(o("$limit", $limit));
        }
        return this;
    }

//    public List<Obj>
}
